package com.wuwei.elearning.question.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wuwei.elearning.config.MinioConfig;
import com.wuwei.elearning.service.CacheService;
import com.wuwei.elearning.enumPackage.Constant;
import com.wuwei.elearning.question.domain.Question;
import com.wuwei.elearning.question.domain.Subject;
import com.wuwei.elearning.question.domain.UserRelationSubject;
import com.wuwei.elearning.question.mapper.QuestionMapper;
import com.wuwei.elearning.question.mapper.SubjectMapper;
import com.wuwei.elearning.question.mapper.SubjectTestRelationQuestionMapper;
import com.wuwei.elearning.question.mapper.UserRelationSubjectMapper;
import com.wuwei.elearning.question.service.SubjectService;
import com.wuwei.elearning.question.vo.SubjectImageVo;
import com.wuwei.elearning.question.vo.SubjectVoForElementUi;
import com.wuwei.elearning.utils.MinioUtil;
import com.wuwei.elearning.utils.MyArrayUtils;
import com.wuwei.elearning.vo.PreviewUrlVo;
import com.wuwei.elearning.vo.SubjectDto;
import com.wuwei.elearning.vo.SubjectVo;
import lombok.SneakyThrows;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author wuwei
 * @since 2024-02-01
 */
@Service
public class SubjectServiceImpl extends ServiceImpl<SubjectMapper, Subject> implements SubjectService {


    @Resource
    private SubjectMapper subjectMapper;

    @Autowired
    private QuestionMapper questionMapper;

    @Resource
    private SubjectTestRelationQuestionMapper subjectTestRelationQuestionMapper;

    /**
     * 获取满足vant要求的数据结构
     *    options: [
     *         {
     *           text: '浙江省',
     *           value: '330000',
     *           children: [{ text: '杭州市', value: '330100' }],
     *         },
     *         {
     *           text: '江苏省',
     *           value: '320000',
     *           children: [{ text: '南京市', value: '320100' }],
     *         },
     *       ],
     * @return
     */
    @Override
    public List<SubjectVo>  getTree() {
        LambdaQueryWrapper<Subject> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(Subject::getName,"M").or().eq(Subject::getName,"综合阅读");
        List<Subject> subjects = subjectMapper.selectList(wrapper);
        List<SubjectVo> list = SubjectVo.convertToTree(subjects);
        return list;
    }


    /**
     * 删除该课程，并把该课程的所有直接子课程的parentId设置为null
     * 删除课程与user关系表中的数据
     * @param id
     */
    @Override
    @Transactional
    public void myDelete(Long id) {
        subjectMapper.setParentIdNull(id);
        subjectMapper.deleteById(id);
        LambdaQueryWrapper<UserRelationSubject> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserRelationSubject::getSubjectId,id);
        userRelationSubjectMapper.delete(wrapper);
    }

    @Override
    public void updateTree(List<SubjectVoForElementUi> subjectVos,Long account ) {
        SubjectVoForElementUi root = new SubjectVoForElementUi();
        root.setChildren(subjectVos);
        List<SubjectVoForElementUi> subjectVoForElementUis = SubjectVoForElementUi.flattenTree(root);
//        for (int i = 1; i < list.size(); i++) {
//            SubjectVo vo = list.get(i);
//            Long value = vo.getValue();
//            Long parentId = vo.getParentId();
//            subjectMapper.setParentId(value,parentId);
//        }
        subjectMapper.setParentId(subjectVoForElementUis,account);
    }

    @Override
    public HashMap<String,Object> getSubjectMapById(Long id) {
        HashMap<String,Object> subjectMapById = subjectMapper.getSubjectMapById(id);
        return subjectMapById;
    }

    @SneakyThrows
    @Override
    @Transactional
    public String mySave(Long account, SubjectDto subjectDto) {
        //新建的课程默认是上架的
        subjectDto.setOnService((short) 1);
        subjectDto.setCreatedBy(account);
        subjectDto.setCreatedTime(LocalDateTime.now());
        subjectMapper.insert(subjectDto);
        Long[] newStudents = subjectDto.getStudents();
        //由于是新添加的课程，暂时还没有子孙，这里不用找
        if (newStudents.length>0) {
            userRelationSubjectMapper.myBatchInsert(subjectDto.getId(),newStudents);
        }
        return setQuestionSubjectId(subjectDto);
    }

    @Override
    @Transactional
    public String myUpdate(Long account, SubjectDto subjectDto) {
        Long subjectId = subjectDto.getId();
        subjectDto.setUpdatedBy(account);
        subjectDto.setUpdatedTime(LocalDateTime.now());
        subjectMapper.updateById(subjectDto);
        Long[] newStudents = subjectDto.getStudents();
        Long[] oldStudents = subjectDto.getOldStudents();
        //把对比newStudents和oldStudents，找出删除的数据和新增的数据
        HashMap<String, Object> differences = MyArrayUtils.<Long>findDifferences(oldStudents, newStudents);
        List<Long> deleteAccounts = (List<Long> )differences.get("A");
        List<Long> addAccounts = (List<Long> )differences.get("B");
        //根据subjectId找出其所有子孙的Id
        List<Long> subjectIds = subjectMapper.getSonsById(subjectId);
        LocalDate endTime = subjectDto.getEndTime();
        LocalDate startTime = subjectDto.getStartTime();
        setSubjectIdsDate(endTime,startTime,subjectIds);
        //删除deleteAccount及其所有子孙的关联

        for (Long deleteAccount : deleteAccounts) {
            LambdaQueryWrapper<UserRelationSubject> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(UserRelationSubject::getAccount,deleteAccount)
                    .in(UserRelationSubject::getSubjectId,subjectIds);
            userRelationSubjectMapper.delete(wrapper);
        }

        //添加addAccounts及其所有子孙的关联
        for (Long addAccount : addAccounts) {
            userRelationSubjectMapper.myBatchInsertByAccount(addAccount,subjectIds);
        }
        return "更新成功！";
    }

    /**
     * 批量设置subject表所有的开始时间和结束时间字段
     * @param endTime
     * @param startTime
     * @param subjectIds
     */
    public void setSubjectIdsDate(LocalDate endTime, LocalDate startTime, List<Long> subjectIds) {
        subjectMapper.setSubjectIdsDate(endTime,startTime,subjectIds);
    }

    @Resource
    private UserRelationSubjectMapper  userRelationSubjectMapper;



    @Override
    public List<Subject> getLeafs() {
        return subjectMapper.getLeafs();
    }

    /**
     * 获取执照课程的叶子节点
     * @return
     */
    @Override
    public List<Subject> getZhizhaoLeafs() {
        return subjectMapper.getZhizhaoLeafs();
    }

    /**
     * 更新subject及其子孙的on_service值
     * @param onService
     * @param id
     * @return
     */
    @Override
    @Transactional
    public String updateService(Short onService, Long id) {
        List<Long> sonsById = subjectMapper.getSonsById(id);
        subjectMapper.batchUpdateOnService(onService,sonsById);
        return onService==1?"上架成功！":"下架成功！";
    }


    @Override
    public String updateNeedTest(Short needTest, Long id) {
        List<Long> sonsById = subjectMapper.getSonsById(id);
        subjectMapper.batchUpdateNeedTest(needTest,sonsById);
        return "更新成功！";
    }

    /**
     * 获取满足vant要求的数据结构
     *    options: [
     *         {
     *           text: '浙江省',
     *           value: '330000',
     *           children: [{ text: '杭州市', value: '330100' }],
     *         },
     *         {
     *           text: '江苏省',
     *           value: '320000',
     *           children: [{ text: '南京市', value: '320100' }],
     *         },
     *       ],
     * @return
     */
    @Override
    public List<SubjectVo> getAllTree() {
        LambdaQueryWrapper<Subject> wrapper = new LambdaQueryWrapper<>();
        List<Subject> subjects = subjectMapper.selectList(wrapper);
        List<SubjectVo> list = SubjectVo.convertToTree(subjects);
        return list;
    }


    /**
     * 获取满足ElementUI要求的数据结构
     * @return
     */
    @Override
    public List<SubjectVoForElementUi> getAllTreeElementUI() {
        LambdaQueryWrapper<Subject> wrapper = new LambdaQueryWrapper<>();
        List<Subject> subjects = subjectMapper.selectList(wrapper);
        List<SubjectVoForElementUi> list = SubjectVoForElementUi.convertToTreeElementUI(subjects);
        return list;
    }

    @Resource
    private CacheService cacheService;

    @Resource
    private MinioUtil minioUtil;

    @Override
    @Transactional
    public PreviewUrlVo uploadCover(MultipartFile file, Long id) {
        String upload = minioUtil.upload(file);
//        subjectMapper.selectById(id).setCover(upload);
        subjectMapper.updateCoverById(upload,id);
        // 然后更新缓存
        String previewUrl = minioUtil.getPreviewUrl(upload);
        previewUrl = minioConfig.getEndpoint()+previewUrl;
        String redisKey = Constant.MINIO_COVER + upload;
        cacheService.setEx(redisKey, previewUrl, 6, TimeUnit.DAYS);
        PreviewUrlVo previewUrlVo = new PreviewUrlVo();
        previewUrlVo.setUrl(previewUrl);
        previewUrlVo.setCover(upload);
        return previewUrlVo;
    }

    @Resource
    private MinioConfig minioConfig;

    @Override
    public SubjectImageVo myGetById(Integer id) {
        SubjectImageVo subject = subjectMapper.mySelectById(id);
        String cover = subject.getCover();
        // 构建Redis键
        String redisKey = Constant.MINIO_COVER + cover;

        String previewUrl;
        // 尝试从Redis获取
        String subjectCover = cacheService.getCover(cover, redisKey);
        subject.setImageUrl(subjectCover);
        return subject;
    }


    @NotNull
    private String setQuestionSubjectId(SubjectDto subjectDto) {
        boolean randomFlag = subjectDto.isRandomQuestion();
        if (!randomFlag) {
            List<Long> questionIds = subjectDto.getQuestionIds();
            if (questionIds != null && !questionIds.isEmpty()) {
                questionMapper.setSubjectId(questionIds,subjectDto.getId());
            }
        } else {
            //随机抽题
            List<Long> questionIds = randomQuestion(subjectDto.getId(),subjectDto.getQuestionNum());
            if (questionIds.size()<subjectDto.getQuestionNum()) {
                return "出题数量超过题库数量，已为您抽题题库最大题目数！";
            } else {
                if (!questionIds.isEmpty()) {
                    questionMapper.setSubjectId(questionIds,subjectDto.getId());
                }
            }
        }
        return "更新成功！";
    }

    /**
     * 随机抽题
     * @param subjectId
     * @param questionNum
     * @return
     */
    private List<Long> randomQuestion(Long subjectId, Integer questionNum) {
        Subject subject = subjectMapper.selectById(subjectId);
        LambdaQueryWrapper<Question> queryWrapper = new LambdaQueryWrapper<>();
        List<Question> questions = questionMapper.selectList(queryWrapper);

        // 如果题目总数小于需要抽取的数量，直接返回所有题目
        if (questions.size() <= questionNum) {
            return questions.stream().map(Question::getId).collect(Collectors.toList());
        }

        // 随机抽取题目
        Collections.shuffle(questions);
        return questions.stream()
                .limit(questionNum)
                .map(Question::getId)
                .collect(Collectors.toList());
    }




}
